package com.yunzhong.appointment.weixin.util;

import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

/**
 * 
 * @className WeixinUtil
 * @description 微信工具类
 * @author 石洪刚
 * @time 2017年10月16日 上午10:26:15
 */
public class WeixinUtil {

	//公众账号ID, 微信支付商户开通后 微信会提供appId和appSecret和商户号mchId
    private static final String appId = "wx54e588f229939c3c";
    private static final String appSecret = "46f81811595da15b51811dc276f734cf";
    //商户号
    private static final String mchId = "1415721202";
    //partnerkey是在商户后台配置的一个32位的key,微信商户平台-账户设置-安全设置-api安全
    private static final String partnerKey = "comturingweixin20161227comturing";
    //微信官方提供的支付api接口
    private static final String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    //微信官方提供的退款api接口
    private static final String refundURL = "https://api.mch.weixin.qq.com/secapi/pay/refund";
    /**
     * 
     * @methodName getCodeUrl
     * @description 得到微信支付二维码的获得路径
     * @author 石洪刚
     * @time 2017年10月16日 上午11:48:08
     * @param notifyUrl  微信通知商户支付结果的请求路径
     * @param outTradeNo 订单编号
     * @param money      订单金额
     * @param attach     附加信息，可不填，会原样返回
     * @param request    请求对象
     * @param response   响应对象
     * @param body       商品的描述信息
     * @return
     */
    public static String getCodeUrl(String notifyUrl, String outTradeNo, String money, String attach, HttpServletRequest request, HttpServletResponse response, String body){
    	//得到随机字符串
    	String nonceStr = UUID.randomUUID().toString().replaceAll("-", "");
    	//总费用
    	String totalFee = getMoney(money);
    	//生成订单客户端所在的IP
    	String spbillCreateIp = request.getRemoteAddr();
    	//支付类型，native为扫码支付
    	String tradeType = "NATIVE";
    	//商品id,当支付方式为native时，必传
    	String productId = outTradeNo;
    	SortedMap<String, String> packageParams = new TreeMap<String, String>();
        packageParams.put("appid", appId);
        packageParams.put("mch_id", mchId);
        packageParams.put("nonce_str", nonceStr);
        packageParams.put("body", body);
        packageParams.put("attach", attach);
        packageParams.put("out_trade_no", outTradeNo);
        packageParams.put("total_fee", totalFee);
        packageParams.put("spbill_create_ip", spbillCreateIp);
        packageParams.put("notify_url", notifyUrl);
        packageParams.put("trade_type", tradeType);
        packageParams.put("product_id", productId);
        RequestHandler reqHandler = new RequestHandler(request, response);//引入微信提供的工具类
        reqHandler.init(appId, appSecret, partnerKey);//调用工具类的初始化方法
        String sign = reqHandler.createSign(packageParams);//得到sign
        //定义xml信息  因为传输信息的方式是用xml
        String xml = "<xml>" +
                "<appid>" + appId + "</appid>" +
                "<attach>" + attach + "</attach>" +
                "<mch_id>" + mchId + "</mch_id>" +
                "<nonce_str>" + nonceStr + "</nonce_str>" +
                "<notify_url>" + notifyUrl + "</notify_url>" +
                "<body><![CDATA[" + body + "]]></body>" +
                "<out_trade_no>" + outTradeNo + "</out_trade_no>" +
                "<product_id>" + productId + "</product_id>" +
                "<spbill_create_ip>" + spbillCreateIp + "</spbill_create_ip>" +
                "<total_fee>" + totalFee + "</total_fee>" +
                "<trade_type>" + tradeType + "</trade_type>" +
                "<sign>" + sign + "</sign>" +
                "</xml>";
        String code_url = "";
        code_url = new GetWxOrderno().getCodeUrl(createOrderURL, xml);
        return code_url;
    }
    /**
     * 
     * @methodName getMoney
     * @description 将金额转换成分
     * @author 石洪刚
     * @time 2017年10月16日 上午11:23:23
     * @param money
     * @return
     */
	private static String getMoney(String money) {
		if(money==null){
            return "";
        }
        // 金额转化为分为单位
        String currency =  money.replaceAll("\\$|\\￥|\\,", "");  //处理包含, ￥ 或者$的金额
        int index = currency.indexOf(".");
        int length = currency.length();
        Long amLong = 0l;
        if(index == -1){
            amLong = Long.valueOf(currency+"00");
        }else if(length - index >= 3){
            amLong = Long.valueOf((currency.substring(0, index+3)).replace(".", ""));
        }else if(length - index == 2){
            amLong = Long.valueOf((currency.substring(0, index+2)).replace(".", "")+0);
        }else{
            amLong = Long.valueOf((currency.substring(0, index+1)).replace(".", "")+"00");
        }
        return amLong.toString();
	}
	/**
	 * 
	 * @methodName chargeBack
	 * @description 微信退单
	 * @author 石洪刚
	 * @time 2017年10月16日 下午2:44:30
	 * @param request
	 * @param response
	 * @param outTradeNo
	 * @param money
	 * @return true代表退单成功，false代表退单失败
	 * @throws Exception
	 */
	public static Boolean chargeBack(HttpServletRequest request, HttpServletResponse response, String outTradeNo, String money) throws Exception{
		//得到随机字符串
    	String nonceStr = UUID.randomUUID().toString().replaceAll("-", "");
    	//用户退单号
    	String outRefundNo = UUID.randomUUID().toString().replaceAll("-", "");
    	//订单金额
    	String totalFee = getMoney(money);
    	//退款金额
    	String refundFee = totalFee;
    	//操作员编号
    	String opUserId = "007";
		SortedMap<String, String> packageParams = new TreeMap<String, String>();
        packageParams.put("appid", appId);//公众账号ID
        packageParams.put("mch_id", mchId);//商户号
        packageParams.put("nonce_str", nonceStr);//随机字符串
        packageParams.put("out_refund_no", outRefundNo);//商户退单号 这里用随机数
        packageParams.put("total_fee",totalFee);//订单金额
        packageParams.put("refund_fee",refundFee);//退款金额
        packageParams.put("op_user_id", opUserId);//操作员编号
        //packageParams.put("transaction_id", dingDan.getWxDingdanhao());//微信订单号 和下面的商户订单号 2选1
        packageParams.put("out_trade_no", outTradeNo);//商户订单号
        //================准备工作搞定====现在开始生成sign=================================
        RequestHandler reqHandler = new RequestHandler(request, response);
        reqHandler.init(appId,appSecret,partnerKey);
        String sign=reqHandler.createSign(packageParams);
        //================准备工作搞定====现在开始生成xml文件===============================
        String xml = "<xml>" +
                "<appid>" + packageParams.get("appid") + "</appid>" +
                "<mch_id>" + packageParams.get("mch_id") + "</mch_id>" +
                "<nonce_str>" + packageParams.get("nonce_str") + "</nonce_str>" +
                "<out_refund_no>" + packageParams.get("out_refund_no") + "</out_refund_no>" +
                "<total_fee>" + packageParams.get("total_fee") + "</total_fee>" +
                "<refund_fee>" + packageParams.get("refund_fee") + "</refund_fee>" +
                "<op_user_id>" + packageParams.get("op_user_id") + "</op_user_id>" +
                "<out_trade_no>" + packageParams.get("out_trade_no") + "</out_trade_no>" +
                "<sign>" + sign + "</sign>" +
                "</xml>";
        //================准备工作搞定====现在开始退单=======================================
        Map<String, String> map = clientCustomSSLCall(refundURL,mchId,xml);//完成退单
        if("SUCCESS".equals(map.get("result_code"))){
        	return true;
        }else{
        	return false;
        }
	}
	/**
	 * 
	 * @methodName clientCustomSSLCall
	 * @description 自定义SSL双向证书验证
	 * @author 石洪刚
	 * @time 2017年10月16日 下午2:37:14
	 * @param refundurl2
	 * @param mchid2
	 * @param xml
	 * @return
	 * @throws Exception 
	 */
	private static Map<String, String> clientCustomSSLCall(String refundURL,
			String mchId, String xml) throws Exception {
		// TODO Auto-generated method stub
        Map<String, String> doXMLtoMap = new HashMap<String, String>();
        //指定读取证书格式为PKCS12  KeyStore是java的密钥库、用来进行通信加密用的、比如数字签名
        KeyStore keyStore = KeyStore.getInstance("PKCS12");  //PKCS12是一种交换数字证书的加密标准
        //读取本机存放的PKCS12证书文件
        FileInputStream instream = new FileInputStream(new File("E:/win10_2016/apiclient_cert.p12"));
        try {
            // 加载keyStore d:\\tomcat.keystore
            keyStore.load(instream, mchId.toCharArray());
        } finally {
            instream.close();
        }
        // 相信自己的CA和所有自签名的证书
        SSLContext sslcontext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, mchId.toCharArray()).build();
        //指定TLS版本 TLS安全传输层协议
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext, new String[] { "TLSv1" }, null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        //设置httpclient的SSLSocketFactory
        CloseableHttpClient httpclient = HttpClients.custom()
                .setSSLSocketFactory(sslsf).build();
        try {
            // 创建http请求(Post方式)
            HttpPost httpPost = new HttpPost(refundURL);
            httpPost.setEntity(new StringEntity(xml, "UTF-8"));
            CloseableHttpResponse response = httpclient.execute(httpPost);

            String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");

            GetWxOrderno getWxOrderno = new GetWxOrderno();
            doXMLtoMap = getWxOrderno.doXMLParse(jsonStr);
            response.close();
        } finally {
            httpclient.close();
        }
        return doXMLtoMap;
	}
}
